package com.yangm.handler;

import com.yangm.core.MiniRpcRequest;
import com.yangm.core.MiniRpcResponse;
import com.yangm.core.RpcServiceHelper;
import com.yangm.MsgStatus;
import com.yangm.protocol.MiniRpcProtocol;
import com.yangm.protocol.MsgHeader;
import com.yangm.protocol.MsgType;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.reflect.FastClass;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

@Slf4j
public class RpcRequestHandler extends SimpleChannelInboundHandler<MiniRpcProtocol<MiniRpcRequest>> {
    private final Map<String, Object> rpcServiceMap;

    public RpcRequestHandler(Map<String, Object> rpcServiceMap) {
        this.rpcServiceMap = rpcServiceMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MiniRpcProtocol<MiniRpcRequest> protocol) {
        RpcRequestProcessor.submitRequest(() -> {
            MiniRpcProtocol<MiniRpcResponse> resProtocol = new MiniRpcProtocol();
            MiniRpcResponse response = new MiniRpcResponse();
            MsgHeader header = protocol.getHeader();
            header.setMsgType((byte) MsgType.RESPONSE.getType());

            MiniRpcRequest request = protocol.getBody();

            String serviceKey = RpcServiceHelper.buildServiceKey(request.getClassName(), request.getServiceVersion());
            Object serviceBean = rpcServiceMap.get(serviceKey);

            if (null == serviceBean) {
                throw new RuntimeException(String.format("service not exist: %s:%s", request.getClassName(), request.getMethodName()));
            }

            Class<?> serviceClass = serviceBean.getClass();
            String methodName = request.getMethodName();
            Class<?>[] parameterTypes = request.getParameterTypes();
            Object[] params = request.getParams();

            FastClass fastClass = FastClass.create(serviceClass);
            int methodIndex = fastClass.getIndex(methodName, parameterTypes);
            Object result;
            try {
                result = fastClass.invoke(methodIndex, serviceBean, params);
                response.setData(result);
                header.setStatus((byte) MsgStatus.SUCCESS.getCode());
                resProtocol.setHeader(header);
                resProtocol.setBody(response);
            } catch (InvocationTargetException e) {
                log.error("process request {} error", header.getRequestId(), e);
                header.setStatus((byte) MsgStatus.FAIL.getCode());
                response.setMsg(e.toString());

            }
            ctx.writeAndFlush(resProtocol);

        });
    }
}
